package scatter.message.rest.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.Assert;
import scatter.common.pojo.form.BasePageQueryForm;
import scatter.common.rest.exception.BusinessDataNotFoundException;
import scatter.common.rest.exception.BusinessException;
import scatter.common.rest.notify.NotifyParam;
import scatter.common.rest.notify.NotifyTool;
import scatter.common.rest.tools.TemplateTool;
import scatter.common.rest.validation.DictService;
import scatter.message.pojo.param.MessageSendParam;
import scatter.message.pojo.po.Message;
import scatter.message.pojo.po.MessageTemplate;
import scatter.message.pojo.po.MessageUserState;
import scatter.message.rest.componentext.MessageSendUserIdsResolver;
import scatter.message.rest.mapper.MessageMapper;
import scatter.message.rest.service.IMessageService;
import scatter.common.rest.service.IBaseAddUpdateQueryFormServiceImpl;
import org.springframework.stereotype.Service;
import scatter.message.pojo.form.MessageAddForm;
import scatter.message.pojo.form.MessageUpdateForm;
import scatter.message.pojo.form.MessagePageQueryForm;
import org.springframework.transaction.annotation.Transactional;
import scatter.message.rest.service.IMessageTemplateService;
import scatter.message.rest.service.IMessageUserStateService;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * <p>
 * 消息表 服务实现类
 * </p>
 *
 * @author yw
 * @since 2021-08-11
 */
@Slf4j
@Service
@Transactional
public class MessageServiceImpl extends IBaseAddUpdateQueryFormServiceImpl<MessageMapper, Message, MessageAddForm, MessageUpdateForm, MessagePageQueryForm> implements IMessageService {



    @Autowired
    private DictService dictService;

    @Autowired(required = false)
    private MessageSendUserIdsResolver messageSendUserIdsResolver;

    @Qualifier("messageSendExecutor")
    @Autowired
    private ExecutorService executorService;

    @Autowired
    private IMessageUserStateService iMessageUserStateService;
    @Autowired
    private IMessageTemplateService iMessageTemplateService;



    @Override
    public void preAdd(MessageAddForm addForm,Message po) {
        super.preAdd(addForm,po);
        // 添加默认未发送状态
        String idByGroupCodeAndValue = dictService.getIdByGroupCodeAndValue(Message.SendStatusDictGroup.message_send_status.groupCode(), Message.SendStatusDictItem.not_send.itemValue());
        po.setSendStatusDictId(idByGroupCodeAndValue);
    }

    @Override
    public void preUpdate(MessageUpdateForm updateForm,Message po) {
        super.preUpdate(updateForm,po);

        // 已发送不能再修改
        Message byId = getById(po.getId());
        String valueById = dictService.getValueById(byId.getSendStatusDictId());
        if (isEqualAny(valueById, Message.SendStatusDictItem.sending.itemValue(), Message.SendStatusDictItem.sent.itemValue())) {
            throw new BusinessException("发送中和已发送的不能修改");
        }

    }

    @Override
    protected void preDeleteById(String id, Message po) {
        super.preDeleteById(id, po);
        String valueById = dictService.getValueById(po.getSendStatusDictId());
        if (isEqualAny(valueById, Message.SendStatusDictItem.sending.itemValue(), Message.SendStatusDictItem.sent.itemValue())) {
            throw new BusinessException("发送中和已发送的不能删除");
        }
    }

    @Override
    public void send(MessageSendParam sendParam) {
        // 已发送不能再修改
        Message byId = getById(sendParam.getMessageId());
        String valueById = dictService.getValueById(byId.getSendStatusDictId());
        if (isEqualAny(valueById, Message.SendStatusDictItem.sending.itemValue(), Message.SendStatusDictItem.sent.itemValue())) {
            throw new BusinessException("发送中和已发送的不能再次发送");
        }
        StopWatch message_send = StopWatch.create("message_send");
        message_send.start();
        // 将消息设置为发送中
        updateSendStatus(byId.getId(),sendParam.getSendUserId(),Message.SendStatusDictItem.sending);

        // 标识是否存在需要发送的用户
        List<CompletableFuture<Void> > futureList = new ArrayList<>();

        // 直接根据用户发送
        CompletableFuture<Void>  userIdsFuture = CompletableFuture.runAsync(() -> {
            message_send.start("userIds");
            doSend(byId, sendParam.getUserIds(), sendParam.getNotifyTypes(), sendParam.getNotifyDetail());
            message_send.stop();
        });
        futureList.add(userIdsFuture);
        if(messageSendUserIdsResolver != null){
            // 根据公司解析用户id
            CompletableFuture<Void> compFuture = CompletableFuture.runAsync(() -> {
                message_send.start("comp");

                // 分页处理
                BasePageQueryForm basePageQueryForm = new BasePageQueryForm().setSize(50L).setCurrent(1L);
                for (; ; ) {
                    ;
                    IPage<String> userIdsPage = messageSendUserIdsResolver.resolverUserIds(sendParam.getCompIds(), MessageSendUserIdsResolver.DataType.comp.name(), basePageQueryForm);
                    // 直到返回数据为空，这里可能会多查询一次，但关系不大
                    if (isEmpty(userIdsPage.getRecords())) {
                        message_send.stop();
                        break;
                    }
                    // 发送
                    doSend(byId, userIdsPage.getRecords(), sendParam.getNotifyTypes(), sendParam.getNotifyDetail());
                    // 下一页
                    basePageQueryForm.setCurrent(basePageQueryForm.getCurrent() + 1);
                }
            });
            // 根据部门解析用户id
            CompletableFuture<Void> deptFuture = CompletableFuture.runAsync(() -> {
                message_send.start("dept");
                // 分页处理
                BasePageQueryForm basePageQueryForm = new BasePageQueryForm().setSize(50L).setCurrent(1L);
                for (; ; ) {
                    IPage<String> userIdsPage = messageSendUserIdsResolver.resolverUserIds(sendParam.getDeptIds(), MessageSendUserIdsResolver.DataType.dept.name(), basePageQueryForm);
                    // 直到返回数据为空，这里可能会多查询一次，但关系不大
                    if (isEmpty(userIdsPage.getRecords())) {
                        message_send.stop();
                        break;
                    }
                    // 发送
                    doSend(byId, userIdsPage.getRecords(), sendParam.getNotifyTypes(), sendParam.getNotifyDetail());
                    // 下一页
                    basePageQueryForm.setCurrent(basePageQueryForm.getCurrent() + 1);
                }
            });

            // 根据角色解析用户id
            CompletableFuture<Void> roleFuture = CompletableFuture.runAsync(() -> {
                message_send.start("role");
                // 分页处理
                BasePageQueryForm basePageQueryForm = new BasePageQueryForm().setSize(50L).setCurrent(1L);
                for (; ; ) {
                    IPage<String> userIdsPage = messageSendUserIdsResolver.resolverUserIds(sendParam.getRoleIds(), MessageSendUserIdsResolver.DataType.role.name(), basePageQueryForm);
                    // 直到返回数据为空，这里可能会多查询一次，但关系不大
                    if (isEmpty(userIdsPage.getRecords())) {
                        message_send.stop();
                        break;
                    }
                    // 发送
                    doSend(byId, userIdsPage.getRecords(), sendParam.getNotifyTypes(), sendParam.getNotifyDetail());
                    // 下一页
                    basePageQueryForm.setCurrent(basePageQueryForm.getCurrent() + 1);
                }
            });

            // 根据岗位解析用户id
            CompletableFuture<Void> postFuture = CompletableFuture.runAsync(() -> {
                message_send.start("post");
                // 分页处理
                BasePageQueryForm basePageQueryForm = new BasePageQueryForm().setSize(50L).setCurrent(1L);
                for (; ; ) {
                    IPage<String> userIdsPage = messageSendUserIdsResolver.resolverUserIds(sendParam.getPostIds(), MessageSendUserIdsResolver.DataType.post.name(), basePageQueryForm);
                    // 直到返回数据为空，这里可能会多查询一次，但关系不大
                    if (isEmpty(userIdsPage.getRecords())) {
                        message_send.stop();
                        break;
                    }
                    // 发送
                    doSend(byId, userIdsPage.getRecords(), sendParam.getNotifyTypes(), sendParam.getNotifyDetail());
                    // 下一页
                    basePageQueryForm.setCurrent(basePageQueryForm.getCurrent() + 1);
                }
            });

            futureList.add(compFuture);
            futureList.add(deptFuture);
            futureList.add(roleFuture);
            futureList.add(postFuture);
        }
        CompletableFuture.allOf((futureList.toArray(new CompletableFuture[futureList.size()])))
                .whenCompleteAsync((result, e)->{
                    // 存在异常
                    if (e == null) {
                        log.error("消息发送结束，存在异常",e);
                        updateSendStatus(byId.getId(),sendParam.getSendUserId(),Message.SendStatusDictItem.send_fail);
                    }else {
                        // 不存在异常
                        updateSendStatus(byId.getId(),sendParam.getSendUserId(),Message.SendStatusDictItem.sent);
                    }
                    log.info(message_send.prettyPrint());

        },executorService);


    }

    @Override
    public boolean updateSendStatus(String messageId,String sendUserId, Message.SendStatusDictItem sendStatusDictItem) {

        Message message = new Message();
        message.setId(messageId);
        String idByGroupCodeAndValue = dictService.getIdByGroupCodeAndValue(Message.SendStatusDictGroup.message_send_status.groupCode(), sendStatusDictItem.name());
        message.setSendStatusDictId(idByGroupCodeAndValue);
        if(sendStatusDictItem == Message.SendStatusDictItem.sending){
            Message byId = getById(messageId);
            if (isStrEmpty(byId.getSendUserId())) {
                message.setSendUserId(sendUserId);
            }
            if (byId.getSendAt() == null) {
                message.setSendAt(LocalDateTime.now());
            }
        }
        return updateById(message);
    }

    @Override
    public Message mapMessageByTemplateCode(String code, Map<String, Object> titleParams, Map<String, Object> contentParams) {
        Assert.hasText(code,"code 不能为空");
        MessageTemplate messageTemplate = iMessageTemplateService.getByCode(code);
        if (messageTemplate == null) {
            throw new BusinessDataNotFoundException(StrUtil.format("模板不存在，code={}",code));
        }
        Message message = new Message();

        String title = TemplateTool.render(messageTemplate.getTitleTpl(),titleParams);
        message.setTitle(title);
        String content = TemplateTool.render(messageTemplate.getContentTpl(),contentParams);
        message.setContent(content);
        // 简短内容取内容的前60个字符
        message.setShortContent(StrUtil.subWithLength(content,0,60));

        return message;
    }

    /**
     * 发送消息
     * @param message
     * @param userIdsList
     * @param notifyTypes
     * @param notifyDetail
     */
    private void doSend(Message message, List<String> userIdsList, List<String> notifyTypes, Map<String,Object> notifyDetail){
        if (isEmpty(userIdsList)) {
            return;
        }
        // 添加消息与用户关系 表数据
        List<MessageUserState> messageUserStates = iMessageUserStateService.sendMessageByUserIds(message, userIdsList, true);
        // 没有插入数据，为空直接返回
        if (isEmpty(messageUserStates)) {
            return;
        }
        // 插入成功，进行通知notify
        NotifyParam notifyParam = NotifyParam.business().setTypes(notifyTypes.stream().collect(Collectors.joining(",")))
                .setTitle(message.getTitle())
                .setToUser(messageUserStates.stream().map(MessageUserState::getUserId).collect(Collectors.toList()))
                .setExt(notifyDetail);
        NotifyTool.notify(notifyParam);


    }
}
